﻿using System.Diagnostics;
using System.Diagnostics.CodeAnalysis;
using System.Globalization;
using System.Text.RegularExpressions;
using DimensionsHelper.Common.Utils;
using DimensionsHelper.LanguageService.Protocol;

namespace DimensionsHelper.LanguageService.Syntax;

public class StringLiteral : Literal<string>
{
    internal StringLiteral(SyntaxNode? parent) :
        base(SyntaxKinds.String, string.Empty, parent)
    {
    }

    /// <summary>
    ///     是否是多行字符串
    /// </summary>
    public bool IsMultiLine { get; internal set; }


    /// <summary>
    ///     默认的空字符
    /// </summary>
    public static StringLiteral Default { get; } = new(null);


    /// <summary>
    ///     判断给定字符串常量是否是<see cref="Default" />
    /// </summary>
    public static bool IsDefault([NotNullWhen(false)] StringLiteral? literal)
    {
        return literal == null || ReferenceEquals(literal, Default);
    }


    /// <summary>
    ///     判断给定的字符串常量是否是空字符串
    /// </summary>
    public static bool IsDefaultOrEmpty([NotNullWhen(false)] StringLiteral? literal)
    {
        return literal == null
               || literal.IsEmpty
               || ReferenceEquals(literal, Default)
               || string.IsNullOrEmpty(literal.Value);
    }
}


public static partial class NodeFactory
{
    public static StringLiteral CreateStringLiteral(SyntaxNode? parent, bool isMultiline, string text)
    {
        return new StringLiteral(parent)
        {
            IsMultiLine = isMultiline,
            Value = text
        };
    }


    public static StringLiteral CreateStringLiteral(SourceNode source)
    {
        Debug.Assert(source.IsNode(SyntaxKinds.String));
        StringLiteral literal = CreateStringLiteral(null,
            source.GetFlags(SyntaxNodeFlags.MultilineString),
            source.Text);
        literal.UpdateFrom(source);
        return literal;
    }
}


/**
 * Date -> Long, Double
 * Operation occurs on the date's double value representation.
 * If the operation involves an invalid date, '####' is returned.
 * 
 * 
 * '+' Operator
 * +-------------+----------------+-------------------+--------------------+--------------------+----------------+
 * |             | Double         | Long              | Text               | Categorical        | Date           |
 * |-------------+----------------+-------------------+--------------------+--------------------+----------------|
 * | Double      | Add Double     | Add Double        | Add Double         | Not applicable     | Add Date       |
 * | Long        | Add Double     | Add Long          | Add Long           | Union Categorical  | Add Date       |
 * | Text        | Add Double     | Add Double        | Concatenation Text | Union Categorical  | Add Date       |
 * | Categorical | Not applicable |	Union Categorical | Union Categorical  | Union Categorical  | Not applicable |
 * | Date        | Add Date       | Add Date          | Add Date           | Not applicable     | Add Date       |
 * +-------------------------------------------------------------------------------------------------------------+
 * 
 * '-' Operator
 * +------------------------------------------------------------------------------------------------------------------+
 * |             | Double          | Long	              | Text                | Categorical         | Date          |
 * |-------------+-----------------+----------------------+---------------------+---------------------+---------------+
 * | Double	     | Subtract Double | Subtract Double      | Subtract Double	    | Not applicable      | Subtract2 Date|
 * | Long        | Subtract Double | Subtract Long        | Subtract Long       | Subtract Categorical|	Subtract2 Date|
 * | Text        | Subtract Double | Subtract Double      | Not applicable      | Subtract Categorical|	Subtract4 Date|
 * | Categorical | Not applicable  | Subtract Categorical | Subtract Categorical| Subtract Categorical|	Not applicable|
 * | Date        | Subtract Date   | Subtract Date	      | Subtract Date       | Not applicable      | Subtract Date |
 * +------------------------------------------------------------------------------------------------------------------+
 */
public static partial class NodeConverter
{
    [GeneratedRegex(@"([a-zA-Z_@#\$][a-zA-Z0-9_@#\$]*)|(\d+)")]
    private static partial Regex CategoryValueRegex();


    private static bool TryConvertToCategory(string value, int startPos, DocumentUri uri,
        [MaybeNullWhen(false)] out CategoryLiteral result)
    {
        result = null;
        Match match = CategoryValueRegex().Match(value);
        if (!match.Success)
        {
            return false;
        }

        // Name
        if (!string.IsNullOrEmpty(match.Groups[0].Value))
        {
            Group idGroup = match.Groups[0];
            Identifier id = NodeFactory.CreateIdentifier(idGroup.Value);
            id.Update(startPos + idGroup.Index, idGroup.Length);
            id.SetUri(uri);

            result = NodeFactory.CreateCategoryLiteral(null, null, id,
                null, null);
            result.UpdateFrom(id);
            return true;
        }

        // Integer
        if (string.IsNullOrEmpty(match.Groups[1].Value))
        {
            return false;
        }

        Group group = match.Groups[1];
        IntegerLiteral integer = NodeFactory.CreateIntegerLiteral(null, int.Parse(group.Value));

        integer.Update(startPos + group.Index, group.Length, group.Value);
        integer.SetUri(uri);

        result = NodeFactory.CreateCategoryLiteral(null, integer);
        result.UpdateFrom(integer);
        return true;
    }


    /// <summary>
    ///     如果字符串可以被转换为分类列表，将返回<see langword="true" />
    /// </summary>
    /// <param name="source">原始字符串节点</param>
    /// <param name="result">转换后的节点</param>
    public static bool TryConvertToCategorical(StringLiteral source,
        [MaybeNullWhen(false)] out CategoricalLiteral result)
    {
        result = null;

        string categories = source.Value;
        int pos = source.Start;

        SyntaxToken? leftCurly = null;
        SyntaxToken? rightCurly = null;

        if (categories.StartsWith('{') && categories.EndsWith('}'))
        {
            leftCurly = NodeFactory.CreateSyntaxToken(SyntaxKinds.LeftCurlyToken);
            leftCurly.Update(source.Start, source.Start + 1, "{");
            leftCurly.SetUri(source.Uri);

            rightCurly = NodeFactory.CreateSyntaxToken(SyntaxKinds.RightCurlyToken);
            rightCurly.Update(source.End - 1, source.End, "}");
            rightCurly.SetUri(source.Uri);

            categories = categories.Substring(1, categories.Length - 2);
            pos++;
        }

        List<CategoryLiteral> items = new();

        foreach (string? element in categories.Split(','))
        {
            if (!string.IsNullOrWhiteSpace(element))
            {
                if (TryConvertToCategory(element, pos, source.Uri, out CategoryLiteral? category))
                {
                    items.Add(category);
                }
                else
                {
                    return false;
                }
            }

            pos += element.Length + 1;
        }

        result = NodeFactory.CreateCategoricalLiteral(null, leftCurly, rightCurly, items);
        result.UpdateFrom(source);
        return true;
    }


    /// <summary>
    ///     尝试将原始字符串节点转换为整数节点（如果字符串是有效数字）。
    /// </summary>
    /// <param name="source">原始字符串</param>
    /// <param name="result">转换后的整数节点</param>
    public static bool TryConvertToInteger(StringLiteral source,
        [MaybeNullWhen(false)] out IntegerLiteral result)
    {
        result = null;
        string str = source.Value;
        int integer = int.MinValue;

        if (source.Width > 2)
        {
            // 16进制整数
            if (str.StartsWith("&H", StringComparison.OrdinalIgnoreCase) &&
                !int.TryParse(str[2..], NumberStyles.HexNumber, CultureInfo.InvariantCulture, out integer))
            {
                return false;
            }

            // 8进制整数
            if (str.StartsWith("&O", StringComparison.OrdinalIgnoreCase) &&
                !str[2..].TryParseOctalNumber(out integer))
            {
                return false;
            }
        }

        if (integer == int.MinValue && !int.TryParse(str.Trim(), out integer))
        {
            return false;
        }

        result = ToInteger(source, integer);
        return true;
    }


    /// <summary>
    ///     尝试将字符串常量节点转换为浮点数节点
    /// </summary>
    /// <param name="source">原始字符串</param>
    /// <param name="result">转换后的浮点数节点</param>
    public static bool TryConvertToDouble(StringLiteral source,
        [MaybeNullWhen(false)] out DoubleLiteral result)
    {
        result = null;

        if (!double.TryParse(source.Value.Trim(), out double doubleValue))
        {
            return false;
        }

        result = ToDouble(source, doubleValue);
        return true;
    }


    /// <summary>
    ///     尝试将字符串转换为布尔值
    /// </summary>
    /// <param name="source">原始字符串</param>
    /// <param name="result">转换后的布尔值常量节点</param>
    public static bool TryConvertToBoolean(StringLiteral source,
        [MaybeNullWhen(false)] out BooleanLiteral result)
    {
        result = null;

        if (!bool.TryParse(source.Value.Trim(), out bool boolValue))
        {
            return false;
        }

        result = ToBoolean(source, boolValue);
        return true;
    }
}